package com.compass.mobile.network.viewmodel


import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.compass.mobile.network.callback.IApiErrorCallback
import com.compass.mobile.network.error.ApiException
import com.compass.mobile.network.error.ERROR
import com.compass.mobile.network.error.ExceptionHandler
import com.compass.mobile.network.flow.requestFlow
import com.compass.mobile.network.response.BaseResponse
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

/**
 * @desc   viewModel基类
 */
open class BaseViewModel : ViewModel() {

    private var limitedCall: Int = 0

    /**
     * 不依赖BaseRepository，运行在主线程中，可直接调用
     * @param errorCall 错误回调
     * @param responseBlock 请求函数
     * @param successBlock 请求回调
     */
    fun <T> launchUIWithResult(
        responseBlock: suspend () -> BaseResponse<T>?,
        errorCall: IApiErrorCallback?,
        successBlock: (T?) -> Unit
    ) {
        launchFlow(errorCall,responseBlock,successBlock)
//        viewModelScope.launch(Dispatchers.Main) {
//            val result = safeApiCallWithResult(errorCall = errorCall, responseBlock)
//            successBlock(result)
//
//
//        }
    }

    /**
     * 不依赖BaseRepository，需要在作用域中运行
     * @param errorCall 错误回调
     * @param responseBlock 请求函数
     */
    private suspend fun <T> safeApiCallWithResult(
        errorCall: IApiErrorCallback?,
        responseBlock: suspend () -> BaseResponse<T>?
    ): T? {
        try {
            val response = withContext(Dispatchers.IO) {
                responseBlock()
            } ?: return null

            if (response.isFailed()) {
                response.msg?.let {
                    throw ApiException(response.code, it)
                }?:kotlin.run {
                    throw ApiException(response.code, ERROR.NOT_FOUND.errMsg)
                }

            }
            return response.data
        } catch (e: Exception) {
            e.printStackTrace()
            val exception = ExceptionHandler.handleException(e)
            if (ERROR.LOGIN_FAILURE.code == exception.errCode) {
                if (limitedCall < 1) {
                    limitedCall++
                    errorCall?.onLoginFail(exception.errCode, ERROR.LOGIN_FAILURE.errMsg)
                }
            } else {
                errorCall?.onError(exception.errCode, exception.errMsg)
            }
        }
        return null
    }


    /**
     * flow 网络请求 测试
     * @param errorCall 错误回调
     * @param requestCall 请求函数
     * @param loadingBlock 是否展示加载框
     * @param successBlock 请求结果
     */
    private  fun <T> launchFlow(
        errorCall: IApiErrorCallback? = null,
        requestCall: suspend () -> BaseResponse<T>?,
        successBlock: (T?) -> Unit
    ) {
        viewModelScope.launch(Dispatchers.Main) {
            val data = requestFlow(errorBlock = { code, error ->
                if (ERROR.NOT_FOUND.code == code) {
                    errorCall?.onLoginFail(code, error)
                } else {
                    errorCall?.onError(code, error)
                }
            }, requestCall)
            successBlock(data)
        }
    }


}